package main

import (
	"fmt"
	"sync"
	"time"
)

/*
	互斥锁：
		避免资源竞争问题，是传统并发编程中对共享资源进行访问控制的主要手段
		sync.Mutex类型只有两个公开的指针方法：Lock和Unlock
		Lock锁定当前的共享资源
		Unlock进行解锁
		互斥锁的本质是当一个goroutine访问时，其他goroutine都不能访问。
		这样在资源同步避免竞争的同事也降低了程序的并发性能，由原本的并行执行变成了串行执行


	读写互斥锁：
		实际上，我们对一个不会变的数据只做读操作的话，是不存在资源竞争问题的
		只要数据不变，不管怎么读取，多少协程同事读取，都是可以的
		所以真正需要互斥的应该是读取-修改，修改-修改之间

		当一个goroutine进行写操作时，其他goroutine既无法读，也无法写
		当一个goroutine进行读操作时，其他goroutine可以读，但无法写

		sync.RWMutex
		写锁定：Lock()
		写解锁：Unlock()
		读锁定：RLock()
		读解锁：RUnlock
*/

var count = 0
var wg sync.WaitGroup
var mutex sync.Mutex
var rwmutex sync.RWMutex

func read() {
	rwmutex.RLock()
	time.Sleep(time.Second * 2)
	fmt.Println("执行读操作***")
	rwmutex.RUnlock()
	wg.Done()
}

func write() {
	rwmutex.Lock()
	fmt.Println("执行写操作")
	time.Sleep(time.Second * 2)
	rwmutex.Unlock()
	wg.Done()
}

func test() {
	rwmutex.Lock()
	count++
	fmt.Println("the count is:", count)
	rwmutex.Unlock()
	time.Sleep(time.Millisecond)
	wg.Done()
}

func main() {
	// // 互斥锁
	// for r := 0; r < 10; r++ {
	// 	wg.Add(1)
	// 	go test()
	// }
	// wg.Wait()

	// 读写互斥锁
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go write()
		wg.Add(1)
		go read()
	}
	wg.Wait()
}
